local desc = dofile "packages/seaborn/pkg/modes/draft/readme.md"

--- banGeneral
--- @param room Room
--- @param gname string
local function banGeneral(room, gname)
  local banned_generals = room:getBanner("@&banned_generals") or {}
  room:findGeneral(gname)
  table.insert(banned_generals, gname)
  room:setBanner("@&banned_generals", banned_generals)
end

--- do draft
---@param room Room
local function doDraft(room)
  -- local kingdom_map = getGeneralsByKingdom(room)
  local all_generals = table.simpleClone(room.general_pile)
  table.shuffle(all_generals)
  local players = room.players
  local viewNum = #all_generals // #players
  local req = Request:new(players, "CustomDialog")
  req.focus_text = "draft_rule"
  for j, p in ipairs(players) do
    local i = j - 1
    local request_data = {
      path = "packages/seaborn/pkg/modes/draft/BanGenerals.qml",
      data = {
        table.slice(all_generals, i * viewNum + 1, j * viewNum),
        {"#ReadyBan"},
        0,
        p.role:endsWith("renegade") and 2 or 1 }
      }
    req:setData(p, request_data)
    req:setDefaultReply(p, {cards = {}})
  end

  local toBan = {}
  for _, p in ipairs(players) do
    local selected = req:getResult(p)
    table.insertTableIfNeed(toBan, selected.cards)
  end
  table.shuffle(toBan)
  table.forEach(toBan, function(p) banGeneral(room, p) end)
end

local draft_getLogic = function()
  ---@class draft_logic : GameLogic
  local draft_logic = GameLogic:subclass("draft_logic")

  function draft_logic:initialize(room)
    GameLogic.initialize(self, room)
    self.role_table = {nil, nil, nil, nil,
      { "lord", "rebel", "renegade", "rebel", "loyalist" },
      { "lord", "rebel", "renegade", "rebel", "loyalist", "rebel" },
      { "lord", "rebel", "renegade", "rebel", "loyalist", "rebel", "loyalist" },
      { "lord", "rebel", "renegade", "rebel", "loyalist", "rebel", "loyalist", "rebel" },
      { "lord", "rebel", "renegade", "rebel", "loyalist", "rebel", "loyalist", "rebel", "loyalist" },
      { "lord", "rebel", "renegade", "rebel", "loyalist", "rebel", "loyalist", "rebel", "loyalist", "rebel" },
    }
  end

  function draft_logic:chooseGenerals()
    local room = self.room ---@class Room
    local generalNum = room.settings.generalNum
    local n = room.settings.enableDeputy and 2 or 1
    doDraft(room)
    local lord = room:getLord()
    local lord_generals = {}
    local lord_num = 3

    if lord ~= nil then
      room:setCurrent(lord)
      local a1 = #room.general_pile
      local a2 = #room.players * generalNum
      if a1 < a2 then
        room:sendLog{
          type = "#NoEnoughGeneralDraw",
          arg = a1,
          arg2 = a2,
          toast = true,
        }
        room:gameOver("")
      end
      lord_num = math.min(a1 - a2, lord_num)
      local generals = table.connect(room:findGenerals(function(g)
        return table.contains(Fk.lords, g)
      end, lord_num), room:getNGenerals(generalNum))
      lord_generals = room:askToChooseGeneral(lord, { generals = generals, n = n })
      local lord_general, deputy
      if type(lord_generals) == "table" then
        deputy = lord_generals[2]
        lord_general = lord_generals[1]
      else
        lord_general = lord_generals
        lord_generals = {lord_general}
      end
      generals = table.filter(generals, function(g)
        return not table.find(lord_generals, function(lg)
          return Fk.generals[lg].trueName == Fk.generals[g].trueName
        end)
      end)
      room:returnToGeneralPile(generals)

      room:prepareGeneral(lord, lord_general, deputy, true)

      room:askToChooseKingdom({lord})
      room:broadcastProperty(lord, "kingdom")

      -- 显示技能
      local canAttachSkill = function(player, skillName)
        local skill = Fk.skills[skillName]
        if not skill then
          fk.qCritical("Skill: "..skillName.." doesn't exist!")
          return false
        end
        if skill:hasTag(Skill.Lord) and not (player.role == "lord" and player.role_shown and room:isGameMode("role_mode")) then
          return false
        end

        if skill:hasTag(Skill.AttachedKingdom) and not table.contains(skill:getSkeleton().attached_kingdom, player.kingdom) then
          return false
        end

        return true
      end

      local lord_skills = {}
      for _, s in ipairs(Fk.generals[lord.general].skills) do
        if canAttachSkill(lord, s.name) then
          table.insertIfNeed(lord_skills, s.name)
        end
      end
      for _, sname in ipairs(Fk.generals[lord.general].other_skills) do
        if canAttachSkill(lord, sname) then
          table.insertIfNeed(lord_skills, sname)
        end
      end

      local deputyGeneral = Fk.generals[lord.deputyGeneral]
      if deputyGeneral then
        for _, s in ipairs(deputyGeneral.skills) do
          if canAttachSkill(lord, s.name) then
            table.insertIfNeed(lord_skills, s.name)
          end
        end
        for _, sname in ipairs(deputyGeneral.other_skills) do
          if canAttachSkill(lord, sname) then
            table.insertIfNeed(lord_skills, sname)
          end
        end
      end
      for _, skill in ipairs(lord_skills) do
        room:doBroadcastNotify("AddSkill", json.encode{
          lord.id,
          skill
        })
      end
    end

    local nonlord = room:getOtherPlayers(lord, true)
    local req = Request:new(nonlord, "AskForGeneral")
    local generals = table.random(room.general_pile, #nonlord * generalNum)
    for i, p in ipairs(nonlord) do
      local arg = table.slice(generals, (i - 1) * generalNum + 1, i * generalNum + 1)
      req:setData(p, { arg, n })
      req:setDefaultReply(p, table.random(arg, n))
    end

    for _, p in ipairs(nonlord) do
      local result = req:getResult(p)
      local general, deputy = result[1], result[2]
      room:findGeneral(general)
      room:findGeneral(deputy)
      room:prepareGeneral(p, general, deputy)
    end

    room:askToChooseKingdom(nonlord)
  end

  return draft_logic
end

local draft = fk.CreateGameMode{
  name = "draft",
  minPlayer = 5,
  maxPlayer = 10,
  logic = draft_getLogic,
  rule = "#draft_rule",
  main_mode = "role_mode",
  winner_getter = function (self, victim)
    if not victim.surrendered and victim.rest > 0 then
      return ""
    end
    local room = victim.room
    local role_map = { ["lord"] = 0, ["loyalist"] = 0, ["rebel"] = 0, ["renegade"] = 0, }

    for _, p in ipairs(room.players) do
      if not p.surrendered and not (p.dead and p.rest == 0) then
        local role = string.endsWith(p.role, "renegade") and "renegade" or p.role
        role_map[role] = role_map[role] + 1
      end
    end

    local winner = ""
    if room:getTag("renegade-standup") then
      if role_map["renegade"] == 0 then
        winner = "lord+loyalist"
      elseif role_map["lord"] + role_map["loyalist"] == 0 then
        for _, p in ipairs(room.players) do
          if not p.surrendered and not (p.dead and p.rest == 0) and string.endsWith(p.role, "renegade") then
            winner = p.role
          end
        end
      end
    else
      if role_map["lord"] == 0 then-- 主公死亡
        if role_map["loyalist"] > 0 or role_map["rebel"] > 0 or role_map["renegade"] > 1 then  -- 忠臣/反贼存活；或者多个内奸存活
          winner = "rebel"
        elseif role_map["renegade"] == 1 then -- 只有一个内奸存活
          for _, p in ipairs(room.players) do
            if not p.surrendered and not (p.dead and p.rest == 0) and string.endsWith(p.role, "renegade") then
              winner = p.role
            end
          end
        else
          return ""
        end
      else -- 主公存活
        if role_map["rebel"] == 0 and role_map["renegade"] == 0 then -- 反贼、内奸死亡
          winner = "lord+loyalist"
        else
          return ""
        end
      end
    end

    return winner
  end,
  surrender_func = function(self, playedTime)
    local roleCheck = false
    local roleText = ""
    local roleTable = {nil, nil, nil, nil,
    { "lord", "rebel", "renegade", "rebel", "loyalist" },
    { "lord", "rebel", "renegade", "rebel", "loyalist", "rebel" },
    { "lord", "rebel", "renegade", "rebel", "loyalist", "rebel", "loyalist" },
    { "lord", "rebel", "renegade", "rebel", "loyalist", "rebel", "loyalist", "rebel" },
    { "lord", "rebel", "renegade", "rebel", "loyalist", "rebel", "loyalist", "rebel", "loyalist" },
    { "lord", "rebel", "renegade", "rebel", "loyalist", "rebel", "loyalist", "rebel", "loyalist", "rebel" },
  }

    local room = Fk:currentRoom()
    local rolesOnfield = table.simpleClone(roleTable[#room.players]) or {}

    for _, p in ipairs(room.players) do
      if p.dead then
        table.removeOne(rolesOnfield, p.role)
      end
    end

    local role_map = {
      ["lord"] = #table.filter(rolesOnfield, function(r) return r == "lord" end),
      ["loyalist"] = #table.filter(rolesOnfield, function(r) return r == "loyalist" end),
      ["rebel"] = #table.filter(rolesOnfield, function(r) return r == "rebel" end),
      ["renegade"] = #table.filter(rolesOnfield, function(r) return string.endsWith(r, "renegade") end),
    }

    if string.endsWith(Self.role, "renegade") then
      local rebelNum = role_map["rebel"]
      local renegadeNum = role_map["renegade"]
      roleCheck = (rebelNum == 0) and (renegadeNum == 1)
      roleText = "left lord and loyalist alive"

    elseif Self.role == "rebel" then
      local rebelNum = role_map["rebel"]
      local renegadeNum = role_map["renegade"]
      roleCheck = (renegadeNum == 0) and (rebelNum == 1)
      roleText = "left one rebel alive"
    elseif Self.role == "loyalist" then
        return { { text = "loyalist never surrender", passed = false } }
    else
      local loyalistNum = role_map["loyalist"]
      local rebelNum = role_map["rebel"]
      local renegadeNum = role_map["renegade"]

      if rebelNum > 0 then -- 1+ rebel, no loyalist, no renegade, no wild
        roleCheck = (renegadeNum == 0) and (loyalistNum == 0)
      else -- no rebel, no loyalist, 1 renegade or 1 wild
        roleCheck = (renegadeNum == 0) and (renegadeNum == 0)
      end

      roleText = "left you alive"
    end

    return {
      { text = roleText, passed = roleCheck },
    }
  end,
  get_adjusted = function(self, player)
    return Fk.game_modes["aaa_role_mode"].getAdjustedProperty(self, player)
  end,
  reward_punish = function (self, victim, killer)
    if not killer or killer.dead then return end
    local rs = victim.room:getTag("renegade-standup")
    if rs and killer.role:endsWith("renegade") then
      killer:drawCards(3, "kill")
    else
      if victim.role == "loyalist" and killer.role == "lord" then
        killer:throwAllCards("he")
      elseif victim.role == "rebel" then
        killer:drawCards(3, "kill")
      end
    end
  end,
}

Fk:loadTranslationTable{
  ["draft"] = "征召模式",
  [":draft"] = desc,
  ["draft_rule"] = "征召模式",
  ["#ReadyBan"] = "确定禁用",
  ["#BanGenerals"] = "禁用武将",
  ["$DraftBanGenerals"] = "选择最多%arg名武将禁用",
  ["@&banned_generals"] = "本局禁用武将",
  ["beta__renegade"] = "内奸",
  ["gama__renegade"] = "内奸",
  ["delta__renegade"] = "内奸",
}

return draft
